package com.github.anastr.speedviewlib;

import com.github.anastr.speedviewlib.components.Indicators.Indicator;
import com.github.anastr.speedviewlib.util.AttrSetUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.MaskFilter;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

public class RaySpeedometer  extends Speedometer{
    private Path markPath = new Path(),
            ray1Path = new Path(),
            ray2Path = new Path();
    private Paint markPaint = new Paint(),
            activeMarkPaint = new Paint(),
            speedBackgroundPaint = new Paint(),
            rayPaint = new Paint();

    private boolean withEffects = true;

    private int degreeBetweenMark = 5;

    
    public RaySpeedometer(Context context) {
        this(context,null);
    }

    public RaySpeedometer(Context context, AttrSet attrSet) {
        this(context, attrSet,"");
    }

    public RaySpeedometer(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        markPaint.setAntiAlias(true);
        activeMarkPaint.setAntiAlias(true);
        speedBackgroundPaint.setAntiAlias(true);
        rayPaint.setAntiAlias(true);
        init();
        initAttributeSet(context, attrSet);
    }

    @Override
    protected void defaultGaugeValues() {
        super.setTextColor(0xFFFFFFFF);
    }

    @Override
    protected void defaultSpeedometerValues() {
        super.setBackgroundCircleColor(0xff212121);
        super.setMarkColor(0xFF000000);
    }

    private void initAttributeSet(Context context, AttrSet attrs) {
        if (attrs == null)
            return;
        rayPaint.setColor(AttrSetUtils.getAttrSetColor(attrs,"sv_rayColor", rayPaint.getColor()));
        int degreeBetweenMark = AttrSetUtils.getInt(attrs,"sv_degreeBetweenMark", this.degreeBetweenMark);
        float markWidth = AttrSetUtils.getDimension(attrs,"sv_markWidth", (int) markPaint.getStrokeWidth());
        markPaint.setStrokeWidth(markWidth);
        activeMarkPaint.setStrokeWidth(markWidth);
        speedBackgroundPaint.setColor(AttrSetUtils.getAttrSetColor(attrs,"sv_speedBackgroundColor"
                , speedBackgroundPaint.getColor()));
        withEffects = AttrSetUtils.getBoolean(attrs,"sv_withEffects", withEffects);
        setWithEffects(withEffects);
        if (degreeBetweenMark > 0 && degreeBetweenMark <= 20)
            this.degreeBetweenMark = degreeBetweenMark;
    }

    private void init() {
        markPaint.setStyle(Paint.Style.STROKE_STYLE);
        markPaint.setStrokeWidth(dpTOpx(3));
        activeMarkPaint.setStyle(Paint.Style.STROKE_STYLE);
        activeMarkPaint.setStrokeWidth(dpTOpx(3));
        rayPaint.setStyle(Paint.Style.STROKE_STYLE);
        rayPaint.setStrokeWidth(dpTOpx(1.8));
        rayPaint.setColor(new Color(0xFFFFFFFF));
        speedBackgroundPaint.setColor(new Color(0xFFFFFFFF));


//        setLayerType(LAYER_TYPE_SOFTWARE, null); TODO 开启硬件加速
        setWithEffects(withEffects);
    }

    @Override
    protected void onSizeChange(int w, int h, int oldW, int oldH) {
        super.onSizeChange(w, h, oldW, oldH);

        updateMarkPath();
        updateBackgroundBitmap();
    }

    @Override
    public void onDrawComponent(Component component, Canvas canvas) {
        super.onDrawComponent(component, canvas);

        canvas.save();
        canvas.rotate(getStartDegree()+90f, getSize() *.5f, getSize() *.5f);
        for (int i = getStartDegree(); i < getEndDegree(); i+=degreeBetweenMark) {
            if (getDegree() <= i) {
                markPaint.setColor(new Color(getMarkColor()));
                canvas.drawPath(markPath, markPaint);
                canvas.rotate(degreeBetweenMark, getSize() *.5f, getSize() *.5f);
                continue;
            }
            if (i > (getEndDegree()- getStartDegree())*getMediumSpeedOffset() + getStartDegree())
                activeMarkPaint.setColor(new Color(getHighSpeedColor()));
            else if (i > (getEndDegree()- getStartDegree())*getLowSpeedOffset() + getStartDegree())
                activeMarkPaint.setColor(new Color(getMediumSpeedColor()));
            else
                activeMarkPaint.setColor(new Color(getLowSpeedColor()));
            canvas.drawPath(markPath, activeMarkPaint);
            canvas.rotate(degreeBetweenMark, getSize() *.5f, getSize()/2f);
        }
        canvas.restore();

        RectFloat speedBackgroundRect = getSpeedUnitTextBounds();
        speedBackgroundRect.left -= 2;
        speedBackgroundRect.right += 2;
        speedBackgroundRect.bottom += 2;
        canvas.drawRect(speedBackgroundRect, speedBackgroundPaint);

        drawSpeedUnitText(canvas);
        drawIndicator(canvas);
        drawNotes(canvas);
    }

    @Override
    protected void updateBackgroundBitmap() {
        Canvas c = createBackgroundBitmapCanvas();

        updateMarkPath();

        ray1Path.reset();
        ray1Path.moveTo(getSize()/2f, getSize()/2f);
        ray1Path.lineTo(getSize()/2f, getSizePa()/3.2f + getCustomPadding());
        ray1Path.moveTo(getSize()/2f, getSizePa()/3.2f + getCustomPadding());
        ray1Path.lineTo(getSize()/2.2f, getSizePa()/3f + getCustomPadding());
        ray1Path.moveTo(getSize()/2.2f, getSizePa()/3f + getCustomPadding());
        ray1Path.lineTo(getSize()/2.1f, getSizePa()/4.5f + getCustomPadding());

        ray2Path.reset();
        ray2Path.moveTo(getSize()/2f, getSize()/2f);
        ray2Path.lineTo(getSize()/2f, getSizePa()/3.2f + getCustomPadding());
        ray2Path.moveTo(getSize()/2f, getSizePa()/3.2f + getCustomPadding());
        ray2Path.lineTo(getSize()/2.2f, getSizePa()/3.8f + getCustomPadding());
        ray2Path.moveTo(getSize()/2f, getSizePa()/3.2f + getCustomPadding());
        ray2Path.lineTo(getSize()/1.8f, getSizePa()/3.8f + getCustomPadding());

        c.save();
        for (int i=0; i<6; i++) {
            c.rotate(58f, getSize() *.5f, getSize() *.5f);
            if (i % 2 == 0)
                c.drawPath(ray1Path, rayPaint);
            else
                c.drawPath(ray2Path, rayPaint);
        }
        c.restore();

        if (getTickNumber() > 0)
            drawTicks(c);
        else
            drawDefMinMaxSpeedPosition(c);
    }

    private void updateMarkPath() {
        markPath.reset();
        markPath.moveTo(getSize() *.5f, getCustomPadding());
        markPath.lineTo(getSize() *.5f, getSpeedometerWidth() + getCustomPadding());
    }


    public boolean isWithEffects() {
        return withEffects;
    }

    public void setWithEffects(boolean withEffects) {
        this.withEffects = withEffects;
        indicatorEffects(withEffects);
        if (withEffects) {
            rayPaint.setMaskFilter(new MaskFilter(3, MaskFilter.Blur.SOLID));
            activeMarkPaint.setMaskFilter(new MaskFilter(5, MaskFilter.Blur.SOLID));
            speedBackgroundPaint.setMaskFilter(new MaskFilter(8, MaskFilter.Blur.SOLID));
        }
        else {
            rayPaint.setMaskFilter(null);
            activeMarkPaint.setMaskFilter(null);
            speedBackgroundPaint.setMaskFilter(null);
        }
        updateBackgroundBitmap();
        invalidate();
    }

    @Override
    public void setIndicator(Indicator.Indicators indicator) {
        super.setIndicator(indicator);
        indicatorEffects(withEffects);
    }

    public int getSpeedBackgroundColor() {
        return speedBackgroundPaint.getColor().getValue();
    }

    public void setSpeedBackgroundColor(int speedBackgroundColor) {
        speedBackgroundPaint.setColor(new Color(speedBackgroundColor));
        updateBackgroundBitmap();
        invalidate();
    }

    public int getDegreeBetweenMark() {
        return degreeBetweenMark;
    }

    /**
     * The spacing between the marks
     * <p>
     *     it should be between (0-20] ,else well be ignore.
     * </p>
     * @param degreeBetweenMark degree between two marks.
     */
    public void setDegreeBetweenMark(int degreeBetweenMark) {
        if (degreeBetweenMark <= 0 || degreeBetweenMark > 20)
            return;
        this.degreeBetweenMark = degreeBetweenMark;
        invalidate();
    }

    public float getMarkWidth() {
        return markPaint.getStrokeWidth();
    }

    public void setMarkWidth(float markWidth) {
        markPaint.setStrokeWidth(markWidth);
        activeMarkPaint.setStrokeWidth(markWidth);
        invalidate();
    }

    public int getRayColor() {
        return rayPaint.getColor().getValue();
    }

    public void setRayColor(int rayColor) {
        rayPaint.setColor(new Color(rayColor));
        updateBackgroundBitmap();
        invalidate();
    }

    /**
     * this Speedometer doesn't use this method.
     * @return {@code Color.TRANSPARENT} always.
     */
    @Deprecated
    @Override
    public int getIndicatorColor() {
        return 0;
    }

    /**
     * this Speedometer doesn't use this method.
     * @param indicatorColor nothing.
     */
    @Deprecated
    @Override
    public void setIndicatorColor(int indicatorColor) {
    }

}
